

#ifndef NODE_H
#define	NODE_H

#include <QtGui>
#include <vector>
#include "Controller.h"

#define useFrame // uncomment to use frame

#ifdef useFrame

class Node : public QFrame {
#else

class Node : public QWidget {
#endif

    Q_OBJECT

public:
    template <typename T>
    T findDirectChild(const QString& name = QString()) {

        foreach(QObject* child, children()) {
            T temp = qobject_cast<T > (child);
            if (temp && (name.isNull() || name == child->objectName()))
                return temp;
        }
        return 0;
    }

    template <typename T>
    const T findDirectChild(const QString& name = QString()) const {

        foreach(QObject* child, children()) {
            T temp = qobject_cast<T > (child);
            if (temp && (name.isNull() || name == child->objectName()))
                return temp;
        }
        return 0;
    }

    Node(QString nodeType, int numChildren, QString operatorSymbol = "");

    virtual QString getNodeType() const; // or operator or operand name
    virtual QString getNodeValue() const; // or operator or operand symbol
    void setLastChild(Node* child);

    /**
     * Indicates if the current node is this type of child node.
     * @return 
     */
    bool isLeftChild() const;
    bool isRightChild() const;
    bool isSingleChild() const;

    /**
     * Will set the specified child node and abort if it is not supported or
     * is already set.
     * @param child
     */
    void setLeftChild(Node* child);
    void setRightChild(Node* child);
    void setSingleChild(Node* child);

    /**
     * Returns a pointer to the specified child node.
     * @return 
     */
    Node* getLeftChild() const;
    Node* getRightChild() const;
    Node* getSingleChild() const;

    virtual QString toCasString() const;
    virtual QString toPrintString() const;
    virtual QString toParseString() const;
    virtual QString toOpenMath() const;
    virtual QString toMathML() const;

    virtual int getInputPosition(bool& found) const;
    virtual void setInputPosition(int& position);
   
    
    /**
     * When ever the a MathEditPoint losses focus it will use
     * this method to propagate that up to the top level node 
     * (NodeTop) and NodeTop can remove empty trees.
     */
    virtual void focusOut();
    
    /**
     * When a leaf node changes size it can call this method to propagate 
     * the size update up to top of tree.
     */
    virtual void upDateSize();

    /**
     * Returns the operators precedence.
     */
    int opPrecedence() const {
        return operatorPrecedence;
    }

    /**
     * Returns true if operation is left to right.
     */
    bool opLeftToRight() const {
        if (operatorPrecedence % 2 == 0) return true;
        else return false;
    }
    
    /**
     * If a top level node that has some equals set it will get all it is equal to.
     * @return 
     */
    virtual std::vector<Node*> getEquals() const;

    /**
     * Identify if this node can be reduced to a value.
     * @return 
     */
    virtual bool isConstant() const;

    /**
     * Get the number of children this node will take.
     * @return 
     */
    int numChildren() const {
        return m_numChildren;
    }

protected:
    /**
     * Returns a pointer to the top node in math item tree.
     * @return 
     */
    virtual Node* getTopNode();
    
    /**
     * Walks up tree and finds Controller in Model class that this node is in.
     * @return 
     */
    virtual Controller* getController();

    int m_index = 0; // the index to place a single child on the node at
private:
    QString m_nodeOperator; // or operator or operand symbol
    QString m_nodeType; // or operator name
    int operatorPrecedence;

    int m_numChildren;
    // if it is zero you can set no children
    // if m_numChildren is one you can set single_child and is single child return true
    // if it is two you can set left and right child


    const QString leftChild = "left_child";
    const QString rightChild = "right_child";
    const QString singleChild = "single_child";
    
    virtual void keyPressEvent(QKeyEvent *event);
};

#endif	/* NODE_H */

